package com.gitee.sqlrest.template;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.FutureTask;

public class Configuration {

  private ConcurrentHashMap<String, FutureTask<SqlTemplate>> templateCache;
  private transient boolean cacheTemplate;
  private Charset charset;

  public Configuration() {
    this(true, Charset.defaultCharset());
  }

  public Configuration(boolean cacheTemplate, Charset charset) {
    super();
    this.cacheTemplate = cacheTemplate;
    this.charset = charset;
    templateCache = new ConcurrentHashMap<>();
  }

  public SqlTemplate getTemplate(final String content) {
    if (null == content || content.isEmpty()) {
      throw new IllegalArgumentException("SQL Content is Empty!");
    }

    if (cacheTemplate) {
      FutureTask<SqlTemplate> f = templateCache.get(content);
      if (f == null) {
        FutureTask<SqlTemplate> ft = new FutureTask<>(() -> createTemplate(content));
        f = templateCache.putIfAbsent(content, ft);
        if (f == null) {
          ft.run();
          f = ft;
        }
      }

      try {
        return f.get();
      } catch (Exception e) {
        templateCache.remove(content);
        throw new RuntimeException(e);
      }

    }

    return createTemplate(content);

  }

  private SqlTemplate createTemplate(String content) {
    SqlTemplate template = new SqlTemplate
        .SqlTemplateBuilder(this, content)
        .build();
    return template;
  }

  public SqlTemplate getTemplate(InputStream in) throws IOException {
    String content;
    try {
      content = readerContent(in);
    } catch (IOException e) {
      throw new IOException("Error reading template ", e);
    }

    return getTemplate(content);

  }

  public SqlTemplate getTemplate(File tplFile) throws FileNotFoundException,
      IOException {
    return this.getTemplate(new FileInputStream(tplFile));
  }

  private String readerContent(InputStream in) throws IOException {
    StringBuilder sb = new StringBuilder(in.available());
    InputStreamReader inputStreamReader = new InputStreamReader(
        new BufferedInputStream(in), charset);
    BufferedReader bufferedReader = new BufferedReader(inputStreamReader);

    String line;
    while ((line = bufferedReader.readLine()) != null) {
      sb.append(line);
    }
    bufferedReader.close();

    return sb.toString();
  }

  public boolean isCacheTemplate() {
    return cacheTemplate;
  }

  public void setCacheTemplate(boolean cacheTemplate) {
    this.cacheTemplate = cacheTemplate;
  }

  public Charset getCharset() {
    return charset;
  }

  public void setCharset(Charset charset) {
    this.charset = charset;
  }

}
